/*
 * complete.c -- the writes awake the readers
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/cdev.h>

#include <linux/completion.h>
#include <linux/sched.h>

/* #include <asm/uaccess.h> */

static dev_t devno;
static struct cdev *completedev;
static int complete_major = 0;

DECLARE_COMPLETION(comp);

/*
 *  struct completion my_completion;
 * init_completion(&my_completion);
 *
 */

ssize_t complete_read(struct file *flip, char __user *buf, size_t count, loff_t *pos)
{
	printk(KERN_INFO "process %i (%s) is going to sleep\n", current->pid, current->comm);
	wait_for_completion(&comp);
	printk(KERN_INFO "wake up process %i (%s)\n", current->pid, current->comm);
	return 0;
}


ssize_t complete_write(struct file *flip, const char __user *buf, size_t count, loff_t *pos)
{
	printk(KERN_INFO "process %i (%s) wakes up readers...\n", current->pid, current->comm);
	complete(&comp);
	return count;
}

static struct file_operations complete_fops = {
	.owner = THIS_MODULE,
	.read  = complete_read,
	.write = complete_write
};

static int complete_init(void)
{
	int result;

	result = alloc_chrdev_region(&devno, 0, 1, "completedev");
	complete_major = MAJOR(devno);

	if (result < 0) {
                printk(KERN_WARNING "completedev: can't get major %d\n", complete_major);
                return result;
        }
	
	completedev = cdev_alloc();
	completedev->ops = &complete_fops;
	result = cdev_add(completedev, devno, 1);
	if (result) {
		printk(KERN_ERR "completedev: Couldn't cdev_add, result=%d\n", result);
		return 1;
	}

	return 0;
}

static void complete_cleanup(void)
{
	cdev_del(completedev);
	unregister_chrdev_region(devno, 1);
}

module_init(complete_init);
module_exit(complete_cleanup);

MODULE_AUTHOR("wangxy");
MODULE_LICENSE("GPL");
 
